package com.javafactroy.kunlong.base.advice;


import ch.qos.logback.classic.Logger;
import com.javafactroy.kunlong.client.feign.consts.ResponseCode;
import com.javafactroy.kunlong.client.feign.dto.ApiResult;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.ServletException;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

@RestControllerAdvice

public class CommonExceptionHandler {
    Logger log = (Logger) LoggerFactory.getILoggerFactory().getLogger("ROOT");

    /**
     * 捕获 自定 异常
     */
//    @ExceptionHandler({BusinessException.class})
//    public ApiResult<?> handleBusinessException(BusinessException ex) {
//        log.error(ex.getMessage(), ex);
//        return ApiResult.fail(ex.getCode(),ex.getMessage());
//    }

    /**
     * 参数缺失异常
     * 说明：参数为必填时，若入参中无此参数则会报MissingServletRequestParameterException
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public ApiResult<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.fail(ResponseCode.ERROR.getCode(), ex.getMessage());
    }

    /**
     * 参数值校验异常
     * {@code @PathVariable} 和 {@code @RequestParam} 参数值校验不通过时抛出的异常处理
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public ApiResult<?> handleConstraintViolationException(ConstraintViolationException ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.fail(ResponseCode.ERROR.getCode(), ex.getMessage());
    }

    /**
     * 参数值类型异常
     * 说明: 定义Integer类型，输入的为String，会出现 MethodArgumentTypeMismatchException异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ApiResult<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
        log.error(ex.getMessage(), ex);
        String message = "参数:" + ex.getName() + " 类型错误";
        return ApiResult.fail(ResponseCode.ERROR.getCode(), message);
    }

    /**
     * {@code @RequestBody} 参数校验不通过时抛出的异常处理
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ApiResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error(ex.getMessage(), ex);
        String msg = ex.getBindingResult().getFieldErrors().stream()
                .map(f -> f == null ? "null" : f.getField() + ": " + f.getDefaultMessage())
                .collect(Collectors.joining(", "));
        return ApiResult.fail(ResponseCode.ERROR.getCode(), msg);
    }

    @ExceptionHandler(BindException.class)
    public ApiResult<?> handleBindException(BindException ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.fail(HttpStatus.BAD_REQUEST.value(),
                ex.getAllErrors().stream()
                        .map(ObjectError::getDefaultMessage)
                        .collect(Collectors.joining("; "))
        );
    }

    /**
     * 捕获 {@code ForbiddenException} 异常
     */
//    @ExceptionHandler({ForbiddenException.class})
//    public Result<?> handleForbiddenException(ForbiddenException ex) {
//        log.error(ex.getMessage(), ex);
//        return Result.failed(ResultEnum.FORBIDDEN);
//    }


    /**
     * 顶级异常捕获并统一处理，当其他异常无法处理时候选择使用
     */
    @ExceptionHandler({Exception.class})
    public ApiResult<?> handle(Exception ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.fail( );
    }

    /**
     * 处理已知的系统异常
     */
    @ExceptionHandler({ServletException.class})
    public ApiResult<?> handle1(Exception ex) {
        log.error(ex.getMessage(), ex);
        return ApiResult.fail(ex.getMessage());
    }

}